#ifndef __tenacitas_id_concept__id_h__
#define __tenacitas_id_concept__id_h__

/** @file */


/** @todo */

// ==> C++ Headers
#include <cstdint>
#include <iostream>
#include <string>
#include <sstream>
#include <cstdlib>
#include <cstring>
#include <cmath>

// ==> 3rds Headers

// ==> Our Headers
#include "string2number.h"

// ==> Namespaces
using namespace std;


// ==> Macro Constants

// ==> Macro Commands


/** ==> namespace of the organization */
namespace tenacitas {
    /** ==> namespace for the project */
    namespace id {
        /** ==> application, bussiness, display, interaction, process, storage,
            transmittion */
        namespace concept {

            // ==> Typedefs 

            // ==> Pre-Declarations

            // ==> Attributes 

            // ==> Functions

            // ==> Classes

            /** 
                @nosubgrouping 
            */
            template <typename tp_value, typename tp_class>
            class t_id {

                // ==> t_id - Friends

                /** Class allowed to access private members of @p t_id, in
                    order to perform tests */
                friend class id_tester;

                /** */
                friend std::ostream & operator<<(std::ostream &p_out,
                                                 const t_id& p_class) {
                    p_out << p_class.m_value;                    
                    return p_out;
                }


                /** */
                friend std::istream & operator>>(std::istream &p_in,
                                                 t_id& p_class) {
                    p_in >> p_class.m_value;
                    return p_in;
                }

            public:

                // ==> t_id - Public Internal Types

                /** */
                typedef tp_value value_t;

                // ==> t_id - Public Constructors

                /** */
                t_id() = delete;

                /** */
                inline t_id(const value_t & p_value) noexcept
                    : m_value(p_value){}
                

                /** */
                inline t_id(value_t && p_value) noexcept {
                    m_value = std::move(p_value);
                }
                

                /** */
                inline t_id(const t_id & p_class) noexcept
                    : m_value(p_class.m_value) {}
                

                /** */
                inline t_id(t_id && p_class) noexcept {
                    m_value = std::move(p_class.m_value);
                }
                

                /**

                   @throw std::invalid_argument
                   @throw std::out_of_range 
                */
                inline t_id(const std::string &p_str) 
                    : m_value(std::move(s2n<value_t>()(p_str))) {} 

                /**

                   @throw std::invalid_argument
                   @throw std::out_of_range 
                */
                inline t_id(const char * p_str) {
                    m_value = std::move(s2n<value_t>()(p_str)); 
                }
                
                /** Destructor */
                inline ~t_id( ){}

                // ==> t_id - Public Accessors

                /** */
                inline value_t value() {
                    return m_value;
                }

                // ==> t_id - Public Operators

                /** */
                inline t_id & operator=(const t_id & p_class) noexcept {
                    if (this != & p_class) {
                        m_value = p_class .m_value;
                    }
                    return *this;
                }

                /** */
                inline t_id & operator=(t_id && p_class) noexcept {
                    if (this != & p_class) {
                        m_value = std::move(p_class.m_value);
                    }
                    return *this;
                }

                /** */
                inline t_id & operator=(value_t && p_value) noexcept {
                    m_value = std::move(p_value);
                    return *this;
                }

                /** */
                inline t_id & operator=(const value_t & p_value) noexcept {
                    m_value = p_value;
                    return *this;
                }
                
                /**

                   @throw std::invalid_argument
                   @throw std::out_of_range 
                */
                inline t_id & operator=(const std::string & p_str) {
                    m_value = std::move(s2n<value_t>(p_str));
                    return *this;
                }

                /**

                   @throw std::invalid_argument
                   @throw std::out_of_range 
                */
                inline t_id & operator=(const char * p_str) {
                    m_value = std::move(s2n<value_t>(p_str)); 
                    return *this;
                }
                
                /** not allowed */
                void* operator new (std::size_t size)
                    throw (std::bad_alloc) = delete; 

                /** not allowed */
                void operator delete (void *p_t_id) = delete;

                /** not allowed */
                void *operator new[] (size_t) = delete;

                /** not allowed */
                void operator delete[] (void *) = delete;

                
                inline bool operator ==(const value_t & p_value) const noexcept {
                    return m_value == p_value;
                }

                /** */
                inline bool operator ==(value_t && p_value) const noexcept {
                    return m_value == std::move(p_value);
                }

                /** */
                inline bool operator ==(value_t & p_value) const noexcept {
                    return m_value == p_value;
                }

                /** */
                inline bool operator ==(const t_id & p_class) const noexcept {
                    return (m_value == p_class.m_value);
                }

                /** */
                inline bool operator !=(const t_id & p_class) const noexcept {
                    return (m_value != p_class.m_value);
                }

                /** */
                inline bool operator >=(const t_id & p_class) const noexcept {
                    return (m_value >= p_class.m_value);
                }

                /** */
                inline bool operator >(const t_id & p_class) const noexcept {
                    return (m_value > p_class.m_value);
                }

                /** */
                inline bool operator <=(const t_id & p_class) const noexcept {
                    return (m_value <= p_class.m_value);
                }

                /** */
                inline bool operator <(const t_id & p_class) const noexcept {
                    return (m_value < p_class.m_value);
                }

            private:

                // ==> t_id - Private Attributes

                /** */
                value_t m_value;
            };
        }
    }
}

// =============================================================================
// I M P L E M E N T A T I O N
// =============================================================================

using namespace tenacitas::id::concept;


#endif


